import socket,select,os
from helpFunc import *
from connbase import *
import hashlib
from cli import *

class tcpRe(tcpReBase):
    def __init__(self,dataPort,numPort,maxConn,cachePerConn,bufSize):
        self.dataPort = dataPort
        self.numPort = numPort        
        tcpReBase.__init__(self,dataPort,numPort,maxConn,cachePerConn,bufSize)        
        self.accepSock = s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)     
        s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        s.bind(('0.0.0.0',con_localPort))
        s.listen(maxConn)
        self.controlSock = self.iniControlSock()
        self.staTime = time.monotonic()
        
    def iniControlSock(self):
        s = socket.socket()
        add = ('127.0.0.1',con_controlPort2)
        s.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
        s.bind(add)
        s.listen(1)
        return s
    
    def start(self,pLen,effTime,inter,lp,k):
        import threading
        def ww():
            a = cli(self.dataPort,self.numPort,pLen,effTime,inter,lp,k)
            while True:
                a.work()
        self.t = t = threading.Thread(target=ww)
        t.setDaemon(True)
        t.start()  
        super().iniSock()
        while True:
            self.dowork()
            
    
    def dealAcc(self):
        csock, caddr = self.accepSock.accept()
        self.connNum += 1
        if self.connNum>self.maxNum:
            csock.close()
            self.connNum -= 1
            print ('too much',self.connNum)
        else:
            id = hashlib.md5(str(uuid.uuid1()).encode()).digest()
            msg = self.makeMsg(askConn_g,id,b'1')                
            print ("ask conn",self.connNum)
            csock.setblocking(0)
            self.idMap[id] = {'sock':csock}
            self.sendMsg(msg)
            
    def dealConnSock(self):
        ss = self.connSock.recv(tcpReadLen)                
        msgList = self.dealData( ss)
        for one in msgList:
            ty,id,da = self.decodeMsg(one)
            re = da[0]
            if  ty==ping_g:
                print('ping back')
            if  ty==connBack_g:
                if re:
                    self.proxySocks[self.idMap[id]['sock']] = {'id':id,'data':b'','peerclose':False,
                                                               'peerFull':False,'tellMyFull':False}
                    print ('askConnBack ok')
                    continue
                self.idMap[id]['sock'].close()
                del self.idMap[id]
                self.connNum -= 1                        
                print ('conn close',self.connNum)
                continue
            self.dealConnsockNormal(id,ty,da)
     
    def dowork(self):   
        if time.monotonic()-self.staTime>10:
            self.staTime = time.monotonic()
            msg = self.makeMsg(ping_g,b'1'*16,b's')                
            self.sendMsg(msg)    
            
        rl = [self.accepSock,self.connSock,self.numSock,self.controlSock]
        if len(self.peerBuf)<tcpReadLen:
            rl += self.getReadSocks()
     
        wl = self.getWriteSocks()
        if self.peerBuf and self.sockWriteLen>0:
            wl.append(self.connSock)
        
        el = []
        rl,wl,el = select.select(rl,wl,el,1)        
        for sock in rl:
            if sock == self.numSock:
                self.numSockRecv()                      
            elif  sock == self.controlSock:
                try:
                    a,b = self.controlSock.accept()
                    st = b''
                    while len(st)!=4:
                        st += a.recv(4)
                    ss = struct.unpack('i',st)[0]
                    a.close()
                    self.dealBufChange(ss)
                    msg = self.makeMsg(bufChange_g,b'1'*16,st)                
                    self.sendMsg(msg)                    
                except Exception as e:
                    print (e)
                    
            elif  sock == self.accepSock:
                self.dealAcc()
            elif sock == self.connSock:
                self.dealConnSock()
            else:
                self.dealProxysocks(sock)
        for sock in wl:
            if sock == self.connSock:
                n = self.connSock.send(self.peerBuf[:self.sockWriteLen])
                self.peerBuf = self.peerBuf[n:]
                self.sockWriteLen -= n
                continue
            self.dealWritesocks(sock)
            
if __name__ == '__main__':
    l = findNPorts(2,socket.SOCK_STREAM)
    t = tcpRe(l[0],l[1],500,200*1024,con_connBufSize)
    t.start(cliPackLen,con_packEffectTime,con_timeoutInternal,22,b'123456')